package org.evolution.util.db;

import java.io.Serializable;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.ConnectionCallback;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.PreparedStatementCreator;
import org.springframework.jdbc.core.ResultSetExtractor;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.SqlTypeValue;
import org.springframework.jdbc.core.StatementCreatorUtils;
import org.springframework.jdbc.core.support.JdbcDaoSupport;

public class EJdbcDaoSupport extends JdbcDaoSupport {

    private static final Logger logger = Logger.getLogger(EJdbcDaoSupport.class);
    public static final String LS = System.getProperty("line.separator");
    private SqlUtil sqlUtil;

    protected boolean nullOrEmpty(Object obj) {
        return obj == null || obj.toString().trim().equals("");
    }

    /**
     * 根据Key在Map中获取长整数，Value可以不是Number类型。
     */
    protected long getLong(Map<String, Object> row, String key) {
        Object obj = row.get(key);
        if (obj == null) {
            return 0;
        } else {
            try {
                return Long.parseLong(obj.toString());
            } catch (NumberFormatException e) {
                return 0;
            }
        }
    }

    /**
     * 根据Key在Map中获取整数，Value可以不是Number类型。
     */
    protected int getInt(Map<String, Object> row, String key) {
        Object obj = row.get(key);
        if (obj == null) {
            return 0;
        } else {
            try {
                return Integer.parseInt(obj.toString());
            } catch (NumberFormatException e) {
                return 0;
            }
        }
    }

    /**
     * @return [sql,params(List),limited]
     */
    private Object[] optimizeMainSql(String sql, int currentPage,
            int rowsPerPage, List<Object> params) {
        List<Object> newParams = null;
        switch (sqlUtil.getDriverType()) {
        case SqlUtil.TYPE_MSSQL_JTDS:
        case SqlUtil.TYPE_MSSQL_MS:
            // 对mssql的优化
            int x = sql.toUpperCase().indexOf("SELECT");
            if (x == -1) {
                return new Object[] { sql, params, Boolean.FALSE };
            }
            int topx = rowsPerPage * currentPage;
            StringBuffer mssql = new StringBuffer(sql.length() + 8);
            // 加入如果出现SELECT DISTINCT的情况的处理
            int distinctX = sql.toUpperCase().indexOf("DISTINCT");
            if (distinctX == (x + 7) || distinctX == (x + 8)) {
                mssql.append(sql.substring(0, distinctX + 8));
                mssql.append(" TOP ");
                mssql.append(topx);
                mssql.append(" ");
                mssql.append(sql.substring(distinctX + 8));
            } else {
                mssql.append(sql.substring(0, x + 6));
                mssql.append(" TOP ");
                mssql.append(topx);
                mssql.append(" ");
                mssql.append(sql.substring(x + 6));
            }

            return new Object[] { mssql.toString(), params, Boolean.FALSE };
        case SqlUtil.TYPE_ORACLE:
            // Oracle优化
            // TODO 需要测试。在有order by的时候，比较复杂的情况可能会有顺序混乱
            StringBuffer oracle = new StringBuffer(sql.length() + 128);
            newParams = new ArrayList<Object>(params);
            if (currentPage == 1) {
                oracle.append("SELECT * FROM (");
            } else {
                // 若页面显示没有固定字段，则从第二页开始会多一列 SYS_ROWNUM.
                oracle
                        .append("SELECT * FROM ( SELECT ROW_.*, ROWNUM SYS_ROWNUM FROM ( ");
            }
            oracle.append(sql);
            Boolean oracleLimited = null;
            if (currentPage == 1) {
                oracle.append(" ) WHERE ROWNUM<=?");
                newParams.add(new Integer(rowsPerPage * currentPage));
                oracleLimited = Boolean.FALSE;
            } else {
                oracle.append(" ) ROW_ WHERE ROWNUM<=? ) WHERE SYS_ROWNUM>=?");
                newParams.add(new Integer(rowsPerPage * currentPage));
                newParams.add(new Integer((currentPage - 1) * rowsPerPage + 1));
                oracleLimited = Boolean.TRUE;
            }
            return new Object[] { oracle.toString(), newParams, oracleLimited };

        case SqlUtil.TYPE_MYSQL:
            // 增加分页对mysql的支持
            StringBuffer mysql = new StringBuffer(sql.length() + 128);
            mysql.append(sql);
            Boolean mySqlLimited = Boolean.FALSE;
            mysql.append(" LIMIT ");
            if (currentPage != 1) {
                mysql.append(rowsPerPage * (currentPage - 1));
                mysql.append(",");
                mySqlLimited = Boolean.TRUE;
            }
            mysql.append(rowsPerPage);
            return new Object[] { mysql.toString(), params, mySqlLimited };
        case SqlUtil.TYPE_POSTGRESQL:
            // 增加分页对postgresql的支持
            StringBuffer postgresql = new StringBuffer(sql.length() + 128);
            postgresql.append(sql);
            Boolean postgresqlLimited = Boolean.FALSE;
            postgresql.append(" LIMIT ");
            postgresql.append(rowsPerPage);
            if (currentPage != 1) {
                postgresql.append(" OFFSET ");
                postgresql.append(rowsPerPage * (currentPage - 1));
                postgresqlLimited = Boolean.TRUE;
            }
            return new Object[] { postgresql.toString(), params,
                    postgresqlLimited };
        default:
            return new Object[] { sql, params, Boolean.FALSE };
        }
    }

    private Object[] optimizeTopxSql(String sql, int topx, List<Object> params) {
        List<Object> newParams = null;
        switch (sqlUtil.getDriverType()) {
        case SqlUtil.TYPE_MSSQL_JTDS:
        case SqlUtil.TYPE_MSSQL_MS:
            // 对mssql的优化
            int x = sql.toUpperCase().indexOf("SELECT");
            if (x == -1) {
                return new Object[] { sql, params, };
            }
            StringBuffer mssql = new StringBuffer(sql.length() + 8);

            // 加入如果出现SELECT DISTINCT的情况的处理
            int distinctX = sql.toUpperCase().indexOf("DISTINCT");
            if (distinctX == (x + 7) || distinctX == (x + 8)) {
                mssql.append(sql.substring(0, distinctX + 8));
                mssql.append(" TOP ");
                mssql.append(topx);
                mssql.append(" ");
                mssql.append(sql.substring(distinctX + 8));
            } else {
                mssql.append(sql.substring(0, x + 6));
                mssql.append(" TOP ");
                mssql.append(topx);
                mssql.append(" ");
                mssql.append(sql.substring(x + 6));
            }

            return new Object[] { mssql.toString(), params };
        case SqlUtil.TYPE_ORACLE:
            // Oracle优化
            // TODO 需要测试。在有order by的时候，比较复杂的情况可能会有顺序混乱
            StringBuffer oracle = new StringBuffer(sql.length() + 128);
            newParams = new ArrayList<Object>(params);
            oracle.append("SELECT * FROM (");
            oracle.append(sql);
            oracle.append(" ) WHERE ROWNUM<=?");
            newParams.add(new Integer(topx));

            return new Object[] { oracle.toString(), newParams };
        case SqlUtil.TYPE_MYSQL:
            // MySql优化
            StringBuffer mySql = new StringBuffer(sql.length() + 128);
            mySql.append(sql);
            mySql.append(" LIMIT ");
            mySql.append(topx);
            return new Object[] { mySql.toString(), params };
        default:
            return new Object[] { sql, params };
        }
    }

    /**
     * 分页查询，也可以仅用来查询某一页的数据。如果countSql不为null，可以用返回的
     * PageData中的id字段获取分页信息或者取消查询。
     * 
     * @param countSql
     *            count sql，如果为null，那么不计算count。
     * @param mainSql
     *            主查询sql
     * @param params
     *            参数列表
     * @param rowsPerPage
     *            每页多少行
     * @param currentPage
     *            当前要获取哪一页，1 based
     * @return PageData:
     *         <table border=1>
     *         <tr>
     *         <td>id</td>
     *         <td>
     *         分页id，根据这个id获取分页信息和取消查询。如果countSql为null
     *         ，那么id为null。</td>
     *         </tr>
     *         <tr>
     *         <td>items</td>
     *         <td>List&lt;Object&gt;</td>
     *         </tr>
     *         <tr>
     *         <td>rowCount</td>
     *         <td>默认值不变</td>
     *         </tr>
     *         <tr>
     *         <td>pageCount</td>
     *         <td>默认值不变</td>
     *         </tr>
     *         <tr>
     *         <td>rowsPerPage</td>
     *         <td>默认值不变</td>
     *         </tr>
     *         <tr>
     *         <td>currentPage</td>
     *         <td>默认值不变</td>
     *         </tr>
     *         </table>
     * @see EJdbcDaoSupport#getCountQueryResult(Serializable)
     * @see EJdbcDaoSupport#cancelCountQuery(Serializable)
     */
    @SuppressWarnings("unchecked")
    protected PageData<?> pageQuery(final String countSql,
            final String mainSql, final List<Object> params,
            final int rowsPerPage, final int currentPage, RowMapper mapper) {
        JdbcTemplate t = getJdbcTemplate();
        final PageData r = new PageData();
        r.setCurrentPage(currentPage);
        r.setRowsPerPage(rowsPerPage);
        final Object[] obj = optimizeMainSql(mainSql, currentPage, r
                .getRowsPerPage(), params);
        final String newSql = (String) obj[0];
        final List mainQueryParams = (List) obj[1];
        final boolean limited = ((Boolean) obj[2]).booleanValue();
        int start;
        if (!limited) {
            start = (currentPage - 1) * rowsPerPage + 1;
        } else {
            start = 1;
        }
        PageDataExtractor pde = new PageDataExtractor(start, rowsPerPage,
                mapper);

        final List data = (List) t.query(new PreparedStatementCreator() {
            public PreparedStatement createPreparedStatement(Connection con)
                    throws SQLException {
                PreparedStatement ps = sqlUtil
                        .preparePageMainQuery(con, newSql, r.getCurrentPage(),
                                r.getRowsPerPage(), limited);
                for (int i = 0; i < mainQueryParams.size(); i++) {
                    StatementCreatorUtils.setParameterValue(ps, i + 1,
                            SqlTypeValue.TYPE_UNKNOWN, null, mainQueryParams
                                    .get(i));
                }
                return ps;
            }
        }, pde);
        r.setItems(data);
        logger.debug(r);
        if (countSql != null) {
            Countor ct = new JdbcCountor(countSql, params, currentPage,
                    rowsPerPage);
            r.setId(PageQueryUtil.add(ct));
        }
        return r;
    }

    /**
     * 查询TopX的数据到List&lt;Object&gt;。
     */
    @SuppressWarnings("unchecked")
    protected List<Object> pageTopxQuery(String sql, List<Object> paras,
            final int topx, final RowMapper mapper) {
        JdbcTemplate t = getJdbcTemplate();
        final Object[] obj = optimizeTopxSql(sql, topx, paras);
        final String newSql = (String) obj[0];
        final List mainQueryParams = (List) obj[1];
        PageDataExtractor pde = new PageDataExtractor(1, topx, mapper);
        final List data = (List) t.query(new PreparedStatementCreator() {
            public PreparedStatement createPreparedStatement(Connection con)
                    throws SQLException {
                PreparedStatement ps = con.prepareStatement(newSql);
                ps.setMaxRows(topx);
                ps.setFetchSize(topx);
                ps.setFetchDirection(ResultSet.FETCH_FORWARD);
                for (int i = 0; i < mainQueryParams.size(); i++) {
                    StatementCreatorUtils.setParameterValue(ps, i + 1,
                            SqlTypeValue.TYPE_UNKNOWN, null, mainQueryParams
                                    .get(i));
                }
                return ps;
            }
        }, pde);
        return data;
    }

    /**
     * 查询TopX的数据到listMap。
     * 
     * @param sql
     * @param paras
     * @param topx
     * @return
     */
    @SuppressWarnings("unchecked")
    protected List<Map<String, Object>> pageTopxListIntoListMap(String sql,
            List<Object> paras, final int topx) {
        List list = pageTopxQuery(sql, paras, topx, new listMapMapper());
        return list;
    }

    /**
     * 分页查询，也可以仅用来查询某一页的数据。如果countSql不为null，可以用返回的
     * PageData中的id字段获取分页信息或者取消查询。
     * 
     * @param countSql
     *            count sql，如果为null，那么不计算count。
     * @param mainSql
     *            主查询sql
     * @param params
     *            参数列表
     * @param rowsPerPage
     *            每页多少行
     * @param currentPage
     *            当前要获取哪一页，1 based
     * @return PageData:
     *         <table border=1>
     *         <tr>
     *         <td>id</td>
     *         <td>
     *         分页id，根据这个id获取分页信息和取消查询。如果countSql为null
     *         ，那么id为null。</td>
     *         </tr>
     *         <tr>
     *         <td>items</td>
     *         <td>
     *         List&lt;Map&lt;String&gt;&lt;Object&gt
     *         ;&gt;</td>
     *         </tr>
     *         <tr>
     *         <td>rowCount</td>
     *         <td>默认值不变</td>
     *         </tr>
     *         <tr>
     *         <td>pageCount</td>
     *         <td>默认值不变</td>
     *         </tr>
     *         <tr>
     *         <td>rowsPerPage</td>
     *         <td>默认值不变</td>
     *         </tr>
     *         <tr>
     *         <td>currentPage</td>
     *         <td>默认值不变</td>
     *         </tr>
     *         </table>
     * @see EJdbcDaoSupport#getCountQueryResult(Serializable)
     * @see EJdbcDaoSupport#cancelCountQuery(Serializable)
     */
    @SuppressWarnings("unchecked")
    protected PageData<Map<String, ?>> pageQueryIntoListMap(String countSql,
            String mainSql, List<Object> params, int rowsPerPage,
            int currentPage) {
        PageData pd = pageQuery(countSql, mainSql, params, rowsPerPage,
                currentPage, new listMapMapper());
        return pd;
    }

    /**
     * 分页查询，也可以仅用来查询某一页的数据。如果countSql不为null，可以用返回的
     * PageData中的id字段获取分页信息或者取消查询。
     * 
     * @param countSql
     *            count sql，如果为null，那么不计算count。
     * @param mainSql
     *            主查询sql
     * @param params
     *            参数列表
     * @param rowsPerPage
     *            每页多少行
     * @param currentPage
     *            当前要获取哪一页，1 based
     * @return PageData:
     *         <table border=1>
     *         <tr>
     *         <td>id</td>
     *         <td>
     *         分页id，根据这个id获取分页信息和取消查询。如果countSql为null
     *         ，那么id为null。</td>
     *         </tr>
     *         <tr>
     *         <td>items</td>
     *         <td>List&lt;List&lt;Object&gt;&gt;</td>
     *         </tr>
     *         <tr>
     *         <td>rowCount</td>
     *         <td>默认值不变</td>
     *         </tr>
     *         <tr>
     *         <td>pageCount</td>
     *         <td>默认值不变</td>
     *         </tr>
     *         <tr>
     *         <td>rowsPerPage</td>
     *         <td>默认值不变</td>
     *         </tr>
     *         <tr>
     *         <td>currentPage</td>
     *         <td>默认值不变</td>
     *         </tr>
     *         </table>
     * @see EJdbcDaoSupport#getCountQueryResult(Serializable)
     * @see EJdbcDaoSupport#cancelCountQuery(Serializable)
     */
    @SuppressWarnings("unchecked")
    protected PageData<List<?>> pageQueryIntoListList(String countSql,
            String mainSql, List<Object> params, int rowsPerPage,
            int currentPage) {
        PageData pd = pageQuery(countSql, mainSql, params, rowsPerPage,
                currentPage, new listListMapper());
        return pd;
    }

    /**
     * 获取count查询的结果。
     * 
     * @param id
     * @return PageData:
     *         <table border=1>
     *         <tr>
     *         <td>id</td>
     *         <td>分页id</td>
     *         </tr>
     *         <tr>
     *         <td>items</td>
     *         <td>没有数据</td>
     *         </tr>
     *         <tr>
     *         <td>rowCount</td>
     *         <td>有数据</td>
     *         </tr>
     *         <tr>
     *         <td>pageCount</td>
     *         <td>有数据</td>
     *         </tr>
     *         <tr>
     *         <td>rowsPerPage</td>
     *         <td>有数据</td>
     *         </tr>
     *         <tr>
     *         <td>currentPage</td>
     *         <td>有数据</td>
     *         </tr>
     *         </table>
     * @see EJdbcDaoSupport#pageQueryIntoListList(String,
     *      String, List, int, int)
     * @see EJdbcDaoSupport#pageQueryIntoListMap(String,
     *      String, List, int, int)
     */
    public PageData<?> getCountQueryResult(Serializable id) {
        Countor c = PageQueryUtil.get(id);
        if (c == null) {
            return new PageData<Object>();
        }
        c.count();
        return c.getPageData();
    }

    /**
     * 取消count查询。
     * 
     * @param id
     * @see EJdbcDaoSupport#pageQueryIntoListList(String,
     *      String, List, int, int)
     * @see EJdbcDaoSupport#pageQueryIntoListMap(String,
     *      String, List, int, int)
     */
    public void cancelCountQuery(Serializable id) {
        Countor c = PageQueryUtil.get(id);
        if (c != null) {
            c.cancel();
        }
    }

    protected ResultSetExtractor listMapExtractor = new ResultSetExtractor() {
        public Object extractData(ResultSet rs) throws SQLException,
                DataAccessException {
            return sqlUtil.getResultSetIntoListMap(rs);
        }
    };

    protected ResultSetExtractor mapExtractor = new ResultSetExtractor() {
        public Object extractData(ResultSet rs) throws SQLException,
                DataAccessException {
            return sqlUtil.getResultSetIntoMap(rs);
        }
    };

    protected ResultSetExtractor listExtractor = new ResultSetExtractor() {
        public Object extractData(ResultSet rs) throws SQLException,
                DataAccessException {
            return sqlUtil.getResultSetIntoList(rs);
        }
    };

    private class JdbcCountor implements Countor {
        private final List<Object> params;
        private final String countSql;
        private int rowCount;
        private PageData<?> pd;

        private PreparedStatement ps = null;

        private int status = INITED;
        private Object lock = this;

        private ConnectionCallback cc = new ConnectionCallback() {
            public Object doInConnection(Connection con) throws SQLException,
                    DataAccessException {
                ResultSet rs = null;
                try {
                    ps = con.prepareStatement(countSql);
                    for (int i = 0; i < params.size(); i++) {
                        StatementCreatorUtils.setParameterValue(ps, i + 1,
                                SqlTypeValue.TYPE_UNKNOWN, null, params.get(i));
                    }
                    status = STARTED;
                    try {
                        rs = ps.executeQuery();// 取消查询可能引起异常，也可能不会
                    } catch (SQLException e) {
                        // 可能是取消查询引起的错误
                        synchronized (lock) {// 先等取消查询的代码释放锁这个时候status已经更新为CANCELED
                            if (status == CANCELED) {
                                logger.info("取消查询引起可忽略的错误：" + e.getMessage());
                                return null;
                            } else {// 普通的错误
                                throw e;
                            }
                        }
                    }
                    synchronized (lock) {
                        if (status == STARTED) {
                            if (rs.next()) {
                                rowCount = rs.getInt(1);
                            } else {
                                rowCount = 0;
                            }
                            status = FINISHED;
                            lock.notifyAll();
                        } else {// cancel
                        }
                        return null;
                    }
                } finally {
                    SqlUtil.close(rs);
                    SqlUtil.close(ps);
                    ps = null;
                }
            }
        };

        private JdbcCountor(String sql, List<Object> params, int page,
                int rowsPerPage) {
            super();
            this.params = params;
            this.countSql = sql;
            pd = new PageData<Object>();
            pd.setCurrentPage(page);
            pd.setRowsPerPage(rowsPerPage);
        }

        public void cancel() {
            synchronized (lock) {
                try {
                    if (ps != null && status == STARTED) {
                        logger.info("取消COUNT查询...");
                        ps.cancel();
                        status = CANCELED;
                    }
                } catch (Exception e) {
                    logger.warn("取消查询失败", e);
                }
                lock.notifyAll();
            }
        }

        public int getStatus() {
            return status;
        }

        public PageData<?> getPageData() {
            return pd;
        }

        public void count() {
            if (status == FINISHED) {
                // 避免两次运行
            }
            switch (status) {
            case INITED:
            case CANCELED:
                logger.debug("count run ...");
                getJdbcTemplate().execute(cc);
                break;
            case STARTED:
                synchronized (lock) {
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        logger.error("", e);
                    }
                }
                break;
            case FINISHED:
                break;
            }
            pd.setRowCount(rowCount);
            pd.count();
        }
    }

    protected class listMapMapper implements org.springframework.jdbc.core.RowMapper {
        private int colCount;
        private int[] colTypes;
        private String[] colNames;
        private boolean inited = false;

        public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
            if (!inited) {
                ResultSetMetaData meta = rs.getMetaData();
                colCount = meta.getColumnCount();
                colTypes = new int[colCount];
                colNames = new String[colCount];
                for (int i = 0; i < colCount; i++) {
                    colTypes[i] = meta.getColumnType(i + 1);
                    colNames[i] = meta.getColumnName(i + 1);
                }
                inited = true;
            }
            Map<String, Object> m = sqlUtil.getRowDataIntoMap(rs, colNames,
                    colTypes);
            return m;
        }
    }

    protected class listListMapper implements RowMapper {
        private int colCount;
        private int[] colTypes;
        private String[] colNames;
        private boolean inited = false;

        public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
            if (!inited) {
                ResultSetMetaData meta = rs.getMetaData();
                colCount = meta.getColumnCount();
                colTypes = new int[colCount];
                colNames = new String[colCount];
                for (int i = 0; i < colCount; i++) {
                    colTypes[i] = meta.getColumnType(i + 1);
                    colNames[i] = meta.getColumnName(i + 1);
                }
                inited = true;
            }
            List<Object> list = new ArrayList<Object>();
            for (int col = 1; col <= colCount; col++) {
                // 把以SYS_开头的列去掉
                if (colNames[col - 1].startsWith("SYS_")) {
                    continue;
                }
                list.add(sqlUtil.getObject(rs, col, colTypes[col - 1]));
            }
            return list;
        }
    }

    private class PageDataExtractor implements ResultSetExtractor {
        private int startRow;
        private int readRowCount;
        private RowMapper mapper;
        private boolean firstGoto = true;

        public PageDataExtractor(int startRow, int readRowCount,
                RowMapper mapper) {
            this.startRow = startRow;
            this.readRowCount = readRowCount;
            this.mapper = mapper;
        }

        private boolean gotoRow(ResultSet rs, int row) throws SQLException {
            if (firstGoto) {
                if (row == 1) {
                    firstGoto = false;
                    return rs.next();
                } else {
                    firstGoto = false;
                    return rs.absolute(row);
                }
            } else {
                return rs.next();
            }
        }

        public Object extractData(ResultSet rs) throws SQLException,
                DataAccessException {
            List<Object> ls = new ArrayList<Object>();
            int row = startRow;
            int count = 0;
            for (; gotoRow(rs, row) && count < readRowCount; row++, count++) {
                Object rowData = mapper.mapRow(rs, row - 1);
                ls.add(rowData);
            }
            return ls;
        }
    }

    public SqlUtil getSqlUtil() {
        return sqlUtil;
    }

    public void setSqlUtil(SqlUtil sqlUtil) {
        this.sqlUtil = sqlUtil;
    }

    /**
     * 屏蔽底层数据库差异的函数，做字符串拼接。 注意：目前支持的数据库不使用自定义函数。 例子：
     * 
     * <pre>
     * 
     * SQL Server
     * funcStrcat(&quot;COLA&quot;,&quot;COLB&quot;) 结果： &quot;COLA + COLB&quot;
     * funcStrcat(&quot;COLA&quot;,&quot;'abc'&quot;) 结果： &quot;COLA + 'abc'&quot;
     * funcStrcat(&quot;COLA&quot;,&quot;?&quot;) 结果： &quot;COLA + ?&quot;
     * </pre>
     */
    protected String funcStrcat(String str1, String str2) {
        return sqlUtil.funcStrcat(str1, str2);
    }

    /**
     * 屏蔽底层数据库差异的函数，做与运算。 注意：目前支持的数据库不使用自定义函数。 例子：
     * 
     * <pre>
     * 
     * SQL Server
     * funcBitAND(&quot;COLA&quot;,&quot;COLB&quot;) 结果： &quot;COLA &amp; COLB&quot;
     * funcBitAND(&quot;COLA&quot;,&quot;123&quot;) 结果： &quot;COLA &amp; 123&quot;
     * funcBitAND(&quot;COLA&quot;,&quot;?&quot;) 结果： &quot;COLA &amp; ?&quot;
     * </pre>
     */
    protected String funcBitAND(String num1, String num2) {
        return sqlUtil.funcBitAND(num1, num2);
    }

    /**
     * 屏蔽底层数据库差异的函数，做或运算。 注意：Oracle需要使用自定义函数。 例子：
     * 
     * <pre>
     * 
     * SQL Server
     * funcBitOR(&quot;COLA&quot;,&quot;COLB&quot;) 结果： &quot;COLA | COLB&quot;
     * funcBitOR(&quot;COLA&quot;,&quot;123&quot;) 结果： &quot;COLA | 123&quot;
     * funcBitOR(&quot;COLA&quot;,&quot;?&quot;) 结果： &quot;COLA | ?&quot;
     * </pre>
     */
    protected String funcBitOR(String num1, String num2) {
        return sqlUtil.funcBitOR(num1, num2);
    }

    /**
     * 屏蔽底层数据库差异的函数，获取从右数第x位的值，x从1开始。 注意：都需要数据库自定义函数。
     * 例子：
     * 
     * <pre>
     * 
     * SQL Server
     * funcBitGet(&quot;COLA&quot;,&quot;COLB&quot;) 结果： &quot;dbo.FUNC_BITGET(COLA,COLB)&quot;
     * funcBitGet(&quot;COLA&quot;,&quot;2&quot;) 结果： &quot;dbo.FUNC_BITGET(COLA,2)&quot;
     * funcBitGet(&quot;COLA&quot;,&quot;?&quot;) 结果： &quot;dbo.FUNC_BITGET(COLA,?)&quot;
     * </pre>
     */
    protected String funcBitGet(String num, String pos) {
        return sqlUtil.funcBitGet(num, pos);
    }

    /**
     * 屏蔽底层数据库差异的函数，获取子串，beginIndex从1开始。
     * 注意：目前支持的数据库不使用自定义函数。 例子：
     * 
     * <pre>
     * 
     * SQL Server
     * funcSubstring(&quot;COLA&quot;,&quot;1&quot;,&quot;5&quot;) 结果： &quot;SUBSTRING(COLA,1,5)&quot;
     * funcSubstring(&quot;COLA&quot;,&quot;?&quot;,&quot;?&quot;) 结果： &quot;SUBSTRING(COLA,?,?)&quot;
     * </pre>
     */
    protected String funcSubstring(String str, String beginIndex, String length) {
        return sqlUtil.funcSubstring(str, beginIndex, length);
    }

    /**
     * 屏蔽底层数据库差异的函数，获取子串，beginIndex从1开始。
     * 注意：目前支持的数据库不使用自定义函数。 例子：
     * 
     * <pre>
     * 
     * SQL Server
     * funcSubstring(&quot;COLA&quot;,&quot;3&quot;) 结果： &quot;SUBSTRING(COLA,3)&quot;
     * funcSubstring(&quot;COLA&quot;,&quot;?&quot;) 结果： &quot;SUBSTRING(COLA,?)&quot;
     * </pre>
     */
    protected String funcSubstring(String str, String beginIndex) {
        return sqlUtil.funcSubstring(str, beginIndex);
    }

    /**
     * 屏蔽底层数据库差异的函数，获取子串下标，beginIndex从1开始。
     * 注意：目前支持的数据库不使用自定义函数。另外，在sqlserver和mysql下
     * 生成的字符串fullStr和strToBeFind的位置会颠倒，因此这两个参数不能都是问号。
     * 例子：
     * 
     * <pre>
     * 
     * SQL Server
     * funcSubstring(&quot;COLA&quot;,&quot;abc&quot;,&quot;5&quot;) 结果： &quot;CHARINDEX(&quot;abc&quot;,COLA,5)&quot;
     * funcSubstring(&quot;COLA&quot;,&quot;?&quot;,&quot;5&quot;) 结果： &quot;CHARINDEX(?,COLA,5)&quot;
     * </pre>
     */
    protected String funcIndexOf(String fullStr, String strToBeFind,
            String beginIndex) {
        return sqlUtil.funcIndexOf(fullStr, strToBeFind, beginIndex);
    }

    /**
     * 屏蔽底层数据库差异的函数，获取子串下标，beginIndex从1开始。
     * 注意：目前支持的数据库不使用自定义函数。另外，仅在sqlserver下
     * 生成的字符串fullStr和strToBeFind的位置会颠倒，因此这两个参数不能都是问号。
     * 例子：
     * 
     * <pre>
     * 
     * SQL Server
     * funcSubstring(&quot;COLA&quot;,&quot;abc&quot;) 结果： &quot;CHARINDEX(&quot;abc&quot;,COLA)&quot;
     * funcSubstring(&quot;COLA&quot;,&quot;?&quot;) 结果： &quot;CHARINDEX(?,COLA)&quot;
     * </pre>
     */
    protected String funcIndexOf(String fullStr, String strToBeFind) {
        return sqlUtil.funcIndexOf(fullStr, strToBeFind);
    }

    /**
     * 屏蔽底层数据库差异的函数，当fullStr为null时,用defaultStr来替换。
     * 注意：目前支持的数据库不使用自定义函数。 例子：
     * 
     * <pre>
     * 
     * SQL Server
     * funcSubstring(&quot;COLA&quot;,&quot;abc&quot;) 结果： &quot;ISNULL(&quot;abc&quot;,COLA)&quot;
     * funcSubstring(&quot;COLA&quot;,&quot;?&quot;) 结果： &quot;ISNULL(?,COLA)&quot;
     * </pre>
     */
    protected String funcIsNull(String fullStr, String defaultStr) {
        return sqlUtil.funcIsNull(fullStr, defaultStr);
    }

    /**
     * 屏蔽底层数据库差异的函数，得到判断字段非空的条件语句
     * 注意只有字段为字符串类型的时候可以使用这个方法。 其他类型的字段会出错。
     * 
     * 例子：
     * 
     * <pre>
     * condSqlIsNotNull("COLUMN1") 
     * 结果：
     * Oracle - "COLUMN1 IS NOT NULL"
     * MySql - "NOT IS NOT NULL AND COLUMN1 <> ''"
     * </pre>
     */
    protected String condIsNotNull(String tableColumn) {
        return sqlUtil.condIsNotNull(tableColumn);
    }

    /**
     * 屏蔽底层数据库差异的函数，得到判断字段为空的条件语句
     * 
     * 例子：
     * 
     * <pre>
     * condSqlIsNull("COLUMN1") 
     * Oracle - "COLUMN1 IS NULL"
     * SqlServer,MySql - "COLUMN1 IS NULL OR COLUMN1 = ''"
     * </pre>
     */
    protected String condIsNull(String tableColumn) {
        return sqlUtil.condIsNull(tableColumn);
    }
}